/*
 *   AS IS License
 * ==Naive Coders==
 */
package org.naive.metawatch.converter.cap;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import org.naive.metawatch.converter.parser.Parseable;
import org.naive.metawatch.converter.parser.Parsed;
import org.naive.metawatch.converter.parser.cap.CapParseContext;

/**
 *
 * @author gbu.000
 */
public class CapConstantPoolComponent extends CapComponent {

    private static final byte CONSTANT_StaticMethodref = (byte) 6;
    private static final byte CONSTANT_StaticFieldref = (byte) 5;
    private static final byte CONSTANT_SuperMethodref = (byte) 4;
    private static final byte CONSTANT_VirtualMethodref = (byte) 3;
    private static final byte CONSTANT_InstanceFieldref = (byte) 2;
    private static final byte CONSTANT_Classref = (byte) 1;
    // manual parsing
    public Parseable[] constantsArray;

    @Override
    public void parse(CapParseContext px) throws ParseException {
        parseHeader(px);
        final List<Parseable> constants= new ArrayList<>();
        final short num = px.readShort();
        for (int i = 0; i < num; i++) {
            Parseable constant = null;
            final byte t = px.readByte();
            switch (t) {
                case CONSTANT_Classref:
                    constant = new ClassRefConstant();
                    break;
                case CONSTANT_InstanceFieldref:
                case CONSTANT_VirtualMethodref:
                case CONSTANT_SuperMethodref:

                    constant = new InstanceMemberConstant(t);
                    break;
                case CONSTANT_StaticMethodref:
                case CONSTANT_StaticFieldref:
                    constant = new StaticMemberConstant(t);
            }
            constant.parse(px);
            constants.add(constant);
        }
        constantsArray = new Parseable[constants.size()];
        constantsArray = constants.toArray(constantsArray);
        
        endParsing(px);
    }
   
    public ClassRefConstant getClassRef(int index) {
        return (ClassRefConstant) constantsArray[index];
    }

    public InstanceMemberConstant getMember(int index) {
        return (InstanceMemberConstant)  constantsArray[index];
    }

    public StaticMemberConstant getStaticMember(int index) {
        return (StaticMemberConstant)  constantsArray[index];
    }

    public static class ClassRefConstant extends Parseable {

        @Parsed(CapClassRef.class)
        public CapClassRef classRef;
        public byte dontCare;
    }

    public static class InstanceMemberConstant extends Parseable {

        private byte tag;
        @Parsed(CapClassRef.class)
        public CapClassRef classRef;
        public byte token;

        public InstanceMemberConstant(byte tag) {
            this.tag = tag;
        }

        public boolean isVirtualMethod() {
            return tag == CONSTANT_VirtualMethodref;
        }

        public boolean isSuperMethod() {
            return tag == CONSTANT_SuperMethodref;
        }

        public boolean isInstanceField() {
            return tag == CONSTANT_InstanceFieldref;
        }
    }

    public static class StaticMemberConstant extends Parseable {

        private byte tag;
        @Parsed(CapStaticMemberRef.class)
        public CapStaticMemberRef ref;

        public StaticMemberConstant(byte tag) {
            this.tag = tag;
        }

        public boolean isStaticField() {
            return tag == CONSTANT_StaticFieldref;
        }

        public boolean isStaticMethod() {
            return tag == CONSTANT_StaticMethodref;
        }
    }
   
}
